package com.hdwe.tools.pm.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hdwe.tools.pm.domain.PmMilestone;
import com.hdwe.tools.pm.domain.PmRequire;
import com.hdwe.tools.pm.domain.PmTask;
import com.hdwe.tools.pm.domain.bo.PmTaskBo;
import com.hdwe.tools.pm.domain.enums.TaskStatus;
import com.hdwe.tools.pm.domain.vo.PmTaskVo;
import com.hdwe.tools.pm.mapper.PmMilestoneMapper;
import com.hdwe.tools.pm.mapper.PmRequireMapper;
import com.hdwe.tools.pm.mapper.PmTaskMapper;
import com.hdwe.tools.pm.service.IPmTaskService;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.service.ComboboxService;
import org.dromara.common.core.service.DictService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.MarkdownUtil;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.WeChatRobot;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.annotation.CacheCombobox;
import org.dromara.common.redis.utils.CacheUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;

import static com.hdwe.tools.pm.config.PmConstant.PM_TASK_DETAIL_PATH;
//import static org.dromara.common.core.utils.WeChatRobot.WEBHOOK_URL;

/**
 * 任务Service业务层处理
 *
 * @author s
 * @date 2024-12-10
 */
@RequiredArgsConstructor
@Service
public class PmTaskServiceImpl implements IPmTaskService {

    private final PmTaskMapper baseMapper;
    private final ComboboxService comboboxService;
    private final DictService dictService;
    private final PmRequireMapper pmRequireMapper;
    private final PmMilestoneMapper pmMilestoneMapper;

    /**
     * 查询任务
     *
     * @param id 主键
     * @return 任务
     */
    @Override
    public PmTaskVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询任务列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 任务分页列表
     */
    @Override
    public TableDataInfo<PmTaskVo> queryPageList(PmTaskBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PmTask> lqw = buildQueryWrapper(bo);
        Page<PmTaskVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的任务列表
     *
     * @param bo 查询条件
     * @return 任务列表
     */
    @Override
    public List<PmTaskVo> queryList(PmTaskBo bo) {
        LambdaQueryWrapper<PmTask> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PmTask> buildQueryWrapper(PmTaskBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getTitle()), PmTask::getTitle, bo.getTitle());
        lqw.eq(bo.getProjectId() != null, PmTask::getProjectId, bo.getProjectId());
        lqw.eq(bo.getRequireId() != null, PmTask::getRequireId, bo.getRequireId());
        lqw.eq(bo.getMilestoneId() != null, PmTask::getMilestoneId, bo.getMilestoneId());
        lqw.eq(StringUtils.isNotBlank(bo.getTaskType()), PmTask::getTaskType, bo.getTaskType());
        lqw.eq(StringUtils.isNotBlank(bo.getPriority()), PmTask::getPriority, bo.getPriority());
        lqw.eq(StringUtils.isNotBlank(bo.getOwner()), PmTask::getOwner, bo.getOwner());
        lqw.eq(bo.getStartDate() != null, PmTask::getStartDate, bo.getStartDate());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), PmTask::getStatus, bo.getStatus());
        lqw.like(StringUtils.isNotBlank(bo.getRelatedUsers()), PmTask::getRelatedUsers, bo.getRelatedUsers());
        return lqw;
    }

    @Override
    public TableDataInfo<PmTaskVo> queryMyTasks(Long userId, PageQuery pageQuery) {
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.eq(PmTask::getOwner, userId);
        Page<PmTaskVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public TableDataInfo<PmTaskVo> queryMyRelatedTasks(Long userId, PageQuery pageQuery) {
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.like(PmTask::getRelatedUsers, userId);
        Page<PmTaskVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public List<PmTaskVo> queryDailyReport(Long userId) {
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.eq(PmTask::getOwner, userId)
            .between(PmTask::getUpdateTime, DateUtil.beginOfDay(new Date()), DateUtil.endOfDay(new Date()))
            .orderByDesc(PmTask::getCreateTime)
            .last("LIMIT 15");;
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public List<PmTaskVo> queryDailyWork(Long userId) {
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.eq(PmTask::getOwner, userId)
            .le(PmTask::getStartDate, DateUtil.beginOfDay(new Date()))
            .notIn(PmTask::getStatus, TaskStatus.FINISHED.getCode(), TaskStatus.CANCELLED.getCode())
            .orderBy(true, true, PmTask::getStatus, PmTask::getStartDate)
            .last("LIMIT 15");
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public List<PmTaskVo> queryWeeklyTasks(Long userId) {
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.eq(PmTask::getOwner, userId);
        lqw.between(PmTask::getUpdateTime, DateUtil.beginOfWeek(new Date()), DateUtil.endOfWeek(new Date()));
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public List<PmTaskVo> queryMilestoneTasks(Long milestoneId) {
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.eq(PmTask::getMilestoneId, milestoneId);
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public List<PmTaskVo> queryRequireTasks(Long requireId) {
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.eq(PmTask::getRequireId, requireId);
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public long queryRequireFinishedRate(Long requireId) {
        List<PmTaskVo> tasks = queryRequireTasks(requireId);
        if (tasks.isEmpty()) {
            return 0;
        }
        long finishedCount = tasks.stream().filter(task -> TaskStatus.FINISHED.getCode().equals(task.getStatus())).count();
        return finishedCount/tasks.size()*100;
    }

    @Override
    public List<PmTaskVo> queryBlockedTasks(Long requireId) {
        LambdaQueryWrapper<PmTask> lqw = Wrappers.lambdaQuery();
        lqw.eq(PmTask::getRequireId, requireId)
            .eq(PmTask::getStatus, TaskStatus.BLOCKED.getCode());
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 新增任务
     *
     * @param bo 任务
     * @return 是否新增成功
     */
    @CacheCombobox(cacheName = CacheNames.COMBOBOX_TASK, keyField = "id", valueField = "title")
    @Override
    public Boolean insertByBo(PmTaskBo bo) {
        PmTask add = MapstructUtils.convert(bo, PmTask.class);
        validEntityBeforeSave(add);
        // 获取对应的需求信息
        Optional.ofNullable(pmRequireMapper.selectById(bo.getRequireId())).ifPresent(r -> add.setEndDate(r.getEndDate()));
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
            sendMsg(bo);
        }
        return flag;
    }

    private void sendMsg(PmTaskBo bo) {
    }

//    private void sendMsg(PmTaskBo bo) {
//        String titleLink = MarkdownUtil.createLink(bo.getTitle(), PM_TASK_DETAIL_PATH + bo.getId());
//        Map<String, String> map = MapUtil.builder("内容", bo.getContent())
//            .put("负责人", comboboxService.queryLabel(CacheNames.COMBOBOX_USER, String.valueOf(bo.getOwner())))
//            .put("优先级", MarkdownUtil.createPriority(dictService.getDictLabel("pm_priorities", bo.getPriority())))
//            .put("关联人", comboboxService.queryLabels(CacheNames.COMBOBOX_USER, String.valueOf(bo.getRelatedUsers())))
//            .put("创建时间", DateUtil.now()).map();
//        WeChatRobot.sendMarkdownMessage(WEBHOOK_URL,"任务", titleLink, map, bo.getRelatedUsers());
//    }

    /**
     * 修改任务
     *
     * @param bo 任务
     * @return 是否修改成功
     */
    @CacheCombobox(cacheName = CacheNames.COMBOBOX_TASK, keyField = "id", valueField = "title")
    @Override
    public Boolean updateByBo(PmTaskBo bo) {
        PmTask update = MapstructUtils.convert(bo, PmTask.class);
        validEntityBeforeSave(update);
        calculateCostTime(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PmTask entity) {
        //TODO 做一些数据校验,如唯一约束
        entity.setEndDate(null);
    }

    private void calculateCostTime(PmTask update) {
        //查询任务信息
        PmTaskVo taskVo = baseMapper.selectVoById(update.getId());
        if (taskVo != null && TaskStatus.FINISHED.ne(taskVo.getStatus()) && TaskStatus.FINISHED.eq(update.getStatus())) {
            //计算任务耗时
            long i = ChronoUnit.HOURS.between(update.getStartDate(), LocalDateTime.now());
            update.setCostTime(i);
            //计算需求耗时
            PmRequire pmRequire = new PmRequire();
            pmRequire.setId(update.getRequireId());
            pmRequire.setCostTime(pmRequire.getCostTime() == null ? i : pmRequire.getCostTime() + i);
            pmRequire.setUpdateTime(new Date());
            pmRequireMapper.updateById(pmRequire);
            //计算小目标耗时
            PmMilestone pmMilestone = new PmMilestone();
            pmMilestone.setId(update.getMilestoneId());
            pmMilestone.setCostTime(pmMilestone.getCostTime() == null ? i : pmMilestone.getCostTime() + i);
            pmMilestone.setUpdateTime(new Date());
            pmMilestoneMapper.updateById(pmMilestone);
        }
    }

    /**
     * 校验并批量删除任务信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @CacheCombobox(cacheName = CacheNames.COMBOBOX_TASK)
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 批量新增需求
     *
     * @param boList 需求
     * @return 是否新增成功
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean batchInsertByBo(List<PmTaskBo> boList) {
        List<PmTask> list = MapstructUtils.convert(boList, PmTask.class);
        if (list != null) list.forEach(e -> {
            validEntityBeforeSave(e);
            //添加缓存
            CacheUtils.put(CacheNames.COMBOBOX_TASK, e.getId(), e.getTitle());
        });
        return baseMapper.insertBatch(list);
    }
}
